// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

#ifndef KEY_MANIFEST_H_
#define KEY_MANIFEST_H_

#include <stdint.h>
#include <stddef.h>
#include "status/rot_status.h"
#include "crypto/rsa.h"
#include "crypto/hash.h"


/**
 * The types of public keys that can be contained in a key manifest.
 */
enum key_manifest_key_type {
	KEY_MANIFEST_RSA_KEY,			/**< An RSA public key. */
	KEY_MANIFEST_ECC_KEY,			/**< An ECc public key. */
};

/**
 * Public key format exposed from the key manifest.
 */
struct key_manifest_public_key {
	enum key_manifest_key_type type;										/**< The type of public key. */
	union {
		struct rsa_public_key rsa;											/**< RSA public key data. */
		struct {
			size_t length;													/**< Length of the ECC public key data. */
			uint8_t der[sizeof (struct rsa_public_key) - sizeof (size_t)];	/**< DER encoded ECC public key. */
		} ecc;
	} key;																	/**< The public key. */
};

/**
 * A platform-independent API for accessing the key manifest.
 */
struct key_manifest {
	/**
	 * Verify that the key manifest is valid.  A valid manifest is one that has a good signature
	 * with a validated key.
	 *
	 * Verification of the key manifest is not guaranteed to be reentrant.
	 *
	 * @param manifest The manifest to validate.
	 * @param hash The hash engine to use for validation.
	 *
	 * @return 0 if the manifest is valid or an error code.
	 */
	int (*verify) (struct key_manifest *manifest, struct hash_engine *hash);

	/**
	 * Check if the key manifest is allowed to be used on this device.  An allowed manifest is one
	 * that has not been revoked.
	 *
	 * @param manifest The manifest to check for permission.
	 *
	 * @return 1 if the manifest is allowed to be used, 0 if it is not, or an error code.
	 */
	int (*is_allowed) (struct key_manifest *manifest);

	/**
	 * Check if the key manifest is configured to revoke any previous manifest.
	 *
	 * @param manifest The manifest to check for updated revocation information.
	 *
	 * @return 1 if the manifest updates the revocation information, 0 if it does not, or an error
	 * code.
	 */
	int (*revokes_old_manifest) (struct key_manifest *manifest);

	/**
	 * Update the device revocation information from the manifest.
	 *
	 * @param manifest The manifest to use for updating the revocation information.
	 *
	 * @return 0 if the revocation information was successfully updated or an error code.
	 */
	int (*update_revocation) (struct key_manifest *manifest);

	/**
	 * Get the public key used to verify application images.
	 *
	 * @param manifest The manifest to get the key from.
	 *
	 * @return The application public key or null if there is an error.  The memory for this key is
	 * managed by the manifest instance.
	 */
	const struct key_manifest_public_key* (*get_app_key) (struct key_manifest *manifest);

	/**
	 * Get the public key used to verify FW manifests.
	 *
	 * @param manifest The manifest to get the key from.
	 *
	 * @return The manifest public key or null if there is an error.  The memory for this key is
	 * managed by the manifest instance.
	 */
	const struct key_manifest_public_key* (*get_manifest_key) (struct key_manifest *manifest);
};


#define	KEY_MANIFEST_ERROR(code)		ROT_ERROR (ROT_MODULE_KEY_MANIFEST, code)

/**
 * Error codes that can be generated by a key manifest.
 */
enum {
	KEY_MANIFEST_INVALID_ARGUMENT = KEY_MANIFEST_ERROR (0x00),		/**< Input parameter is null or not valid. */
	KEY_MANIFEST_NO_MEMORY = KEY_MANIFEST_ERROR (0x01),				/**< Memory allocation failed. */
	KEY_MANIFEST_VERIFY_FAILED = KEY_MANIFEST_ERROR (0x02),			/**< An error not related to validation caused verification to fail. */
	KEY_MANIFEST_IS_ALLOWED_FAILED = KEY_MANIFEST_ERROR (0x03),		/**< Unable to determine if the manifest is revoked. */
	KEY_MANIFEST_REVOKE_CHECK_FAILED = KEY_MANIFEST_ERROR (0x04),	/**< Unable to determine if the manifest revokes an old manifest. */
	KEY_MANIFEST_REVOKE_UPDATE_FAILED = KEY_MANIFEST_ERROR (0x05),	/**< Revocation was not updated. */
	KEY_MANIFEST_BAD_ROOT_KEY = KEY_MANIFEST_ERROR (0x06),			/**< The root key in the manifest is not valid. */
	KEY_MANIFEST_INVALID_FORMAT = KEY_MANIFEST_ERROR (0x07),		/**< The manifest is not formatted correctly. */
	KEY_MANIFEST_UNSUPPORTED_KEY = KEY_MANIFEST_ERROR (0x08),		/**< A key in the manifest is not supported. */
	KEY_MANIFEST_UNSUPPORTED_CERT = KEY_MANIFEST_ERROR (0x09),		/**< A certificate in the manifest is not supported. */
	KEY_MANIFEST_WEAK_KEY = KEY_MANIFEST_ERROR (0x0a),				/**< A key in the manifest does not meet security requirements. */
	KEY_MANIFEST_UNTRUSTED_ROOT_KEY = KEY_MANIFEST_ERROR (0x0b),	/**< A valid root key is not trusted (e.g. revoked by hardware). */
};


#endif /* KEY_MANIFEST_H_ */
